package com.spring.framework.aop.xml.around;

import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;

/**
 * 环绕通知
 * <p>
 * 环绕通知使用< aop:around >标签配置，并且通常情况下，环绕通知都是独立使用的，即其他通知基本上可以相互配合，但是如果配置了环绕通知，
 * 那么基本上不会配置其他四种通知。
 * <p>
 * 环绕通知的方法的第一个参数必须是ProceedingJoinPoint类型，在通知逻辑（方法体）中，对ProceedingJoinPoint调用proceed()方法将会导
 * 致执行切入点方法的逻辑，proceed()的返回的值就是切入点方法的返回值，我们可以对该返回值进行加工，而环绕通知方法的返回值就是外部调用切
 * 入点方法获取的最终返回值，如果没有返回值，那么外部调用切入点方法获取的最终返回值为null。环绕通知的返回值类型应该和切入点方法的返回值
 * 类型一致或者兼容。
 * <p>
 * proceed方法还能传递一个数组，该数组就是切入点方法所需的参数。可以通过对ProceedingJoinPoint调用getArgs获取外部调用切入点方法时传递
 * 进来的参数数组，也可以在环绕通知的逻辑中自己设置参数。
 * <p>
 * 我们可以在可以在环绕通知的方法主体中调用proceed方法一次、多次或根本不调用，所有这些都是合法的。这就是上面所说的可以控制切入点方法到底
 * 什么时候执行、怎么执行的功能。因此一个around advice在一定程度上具有前面四个通知的全部功能！
 *
 * @author xuweizhi
 */
@SuppressWarnings("all")
public class AopAspectAround {

	/**
	 * 一定要有ProceedingJoinPoint类型的参数
	 */
	public int around(ProceedingJoinPoint pjp) {
		int finalReturn = 0;
		Object[] args = pjp.getArgs();
		System.out.println("外部传递的参数: " + Arrays.toString(args));
		System.out.println("==前置通知==");
		try {
			//proceed调用切入点方法，args表示参数，proceed就是切入点方法的返回值
			Object proceed = pjp.proceed(args);
			//也可以直接掉用proceed方法，它会自动传递参数外部的参数
			//Object proceed = pjp.proceed(args);
			System.out.println("切入点方法的返回值: " + proceed);
			System.out.println("==后置通知==");
			finalReturn = (int) proceed;
		} catch (Throwable throwable) {
			throwable.printStackTrace();
			System.out.println("==异常通知==");
			finalReturn = 444;
		} finally {
			System.out.println("==最终通知==");
		}
		//外部调用切入点方法获取的最终返回值
		return finalReturn;
	}
}
